﻿@using Gurux.DLMS.AMI.Shared.DIs
@using Gurux.DLMS.AMI.Shared.DTOs.Agent
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Gurux.DLMS.AMI.Shared.DTOs
@using Gurux.DLMS.AMI.Shared.DTOs.Authentication
@using Gurux.DLMS.AMI.Shared.Rest
@using Microsoft.AspNetCore.SignalR.Client
@using Gurux.DLMS.AMI.Shared
@using Gurux.DLMS.AMI.Shared.Enums
@using Gurux.DLMS.AMI.Client.Helpers
@using Gurux.DLMS.AMI.Module
@using System.Linq

@inject HttpClient Http
@inject IGXNotifier Notifier

<SelectionContainer TItem="GXAgent" @ref="@_selectionContainer">
    <SelectionList Title="Selected" @ref="_selected"
                   ShowAllUsers="false"
                   ItemsProvider="@GetSelectedItems"
                   OnAdded="OnAdded"
                   OnRemoved="@Removed">
        <DataContent>
            @context.Name
        </DataContent>
        <FilterContent>
            <Search Placeholder="@Properties.Resources.FilterByName"
                    OnClickAsync="@SearchSelectedByName" />
        </FilterContent>
        <ButtonContent>
            <div>
                <button style="float: right;" class="btn btn-outline-secondary border-left-0 border"
                        type="button" onclick="@(() => RemoveAll())">
                    &raquo;
                </button>
            </div>
        </ButtonContent>
    </SelectionList>
    <SelectionList Title="Available" @ref="_available"
                   ItemsProvider="@GetItems">
        <DataContent>
            @context.Name
        </DataContent>
        <FilterContent>
            <Search Placeholder="@Properties.Resources.FilterByName"
                    OnClickAsync="@SearchByName" />
            <Search Placeholder="@Properties.Resources.FilterByUser"
                    OnClickAsync="@SearchByUser" />
        </FilterContent>
        <ButtonContent>
            <div>
                <button style="float: left;" class="btn btn-outline-secondary border-left-0 border"
                        type="button" onclick="@(() => AddAll())">
                    &laquo;
                </button>
            </div>
        </ButtonContent>
    </SelectionList>
</SelectionContainer>

@code {

    [CascadingParameter]
    private AgentGroupTab? Parent { get; set; }

    /// <summary>
    /// Selected agents.
    /// </summary>
    [Parameter]
    public List<GXAgent>? Agents { get; set; }

    SelectionList<GXAgent>? _selected;
    SelectionList<GXAgent>? _available;
    SelectionContainer<GXAgent>? _selectionContainer;
    /// <summary>
    /// Agent filter.
    /// </summary>
    private GXAgent filter = new GXAgent(null);
    /// <summary>
    /// Selected agent filter.
    /// </summary>
    private GXAgent selectedFilter = new GXAgent();

    protected async Task SearchSelectedByName(string? name)
    {
        try
        {
            if (_selected != null)
            {
                selectedFilter.Name = name;
                await _selected.RefreshDataAsync();
            }
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }

    protected async Task SearchByName(string? name)
    {
        try
        {
            if (_available != null)
            {
                filter.Name = name;
                Notifier?.ClearStatus();
                await _available.RefreshDataAsync();
            }
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }

    protected async Task SearchByUser(string? userName)
    {
        try
        {
            if (_available != null)
            {
                if (string.IsNullOrEmpty(userName))
                {
                    filter.AgentGroups = null;
                }
                else
                {
                    GXUser user;
                    GXAgentGroup? ag = filter.AgentGroups?.FirstOrDefault();
                    if (ag == null)
                    {
                        ag = new GXAgentGroup();
                        user = new();
                        GXUserGroup? ug = new GXUserGroup();
                        ag.UserGroups = new List<GXUserGroup>(new GXUserGroup[] { ug });
                        ug.Users = new List<GXUser>(new GXUser[] { user });
                        filter.AgentGroups = new List<GXAgentGroup>(new GXAgentGroup[] { ag });
                    }
                    else
                    {
                        user = ag.UserGroups[0].Users[0];
                    }
                    user.UserName = userName;
                }
                Notifier?.ClearStatus();
                await _available.RefreshDataAsync();
            }
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }

    /// <summary>
    /// Add all objects to selected items.
    /// </summary>
    /// <returns></returns>
    private async Task AddAll()
    {
        int max = 0;
        //max 1000 items are added at the one time.
        if (_available != null && _available.TotalCount > 1000)
        {
            max = 1000;
        }
        var ret = await GetItems(new GXItemsProviderRequest(0, max));
        await OnAdded(ret.Items);
        if (_selected != null)
        {
            await _selected.RefreshDataAsync();
        }
        if (_available != null)
        {
            await _available.RefreshDataAsync();
        }
    }

    /// <summary>
    /// Remove all objects from selected items.
    /// </summary>
    /// <returns></returns>
    private async Task RemoveAll()
    {
        List<GXAgent> devs = GetAgents();
        devs.Clear();
        if (_selected != null)
        {
            await _selected.RefreshDataAsync();
        }
        if (_available != null)
        {
            await _available.RefreshDataAsync();
        }
    }

    /// <summary>
    /// New device is added for selection list.
    /// </summary>
    public async Task OnAdded(IEnumerable<GXAgent> items)
    {
        List<GXAgent> agents = GetAgents();
        agents.InsertRange(0, items);
        if (_selected != null)
        {
            await _selected.RefreshDataAsync();
        }
    }

    /// <summary>
    /// Device has removed from the lists.
    /// </summary>
    private async Task Removed(IEnumerable<GXAgent> items)
    {
        List<GXAgent> agents = GetAgents();
        agents.RemoveAll(w => items.Contains(w));
        if (_selected != null)
        {
            await _selected.RefreshDataAsync();
        }
    }

    private List<GXAgent> GetAgents()
    {
        if (Agents != null)
        {
            return Agents;
        }
        return Parent.Active.Agents;
    }

    /// <summary>
    /// Filter is done when SearchSelectedByName is called.
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    private ValueTask<ItemsProviderResult<GXAgent>> GetSelectedItems(GXItemsProviderRequest request)
    {
        var agents = GetAgents();
        int total = agents.Count;
        if (!string.IsNullOrEmpty(selectedFilter.Name))
        {
            agents = agents.Where(w => w.Name.ToLower().Contains(selectedFilter.Name.ToLower())).ToList();
        }
        return new(new ItemsProviderResult<GXAgent>(
        agents.Skip(request.StartIndex).Take(request.Count), total));
    }

    private async ValueTask<ItemsProviderResult<GXAgent>> GetItems(GXItemsProviderRequest request)
    {
        //Don't clear status or error is lost.
        Notifier?.ProgressStart();
        try
        {
            ListAgents req = new ListAgents()
                {
                    Index = request.StartIndex,
                    Count = request.Count,
                    Filter = filter,
                    Descending = request.Descending,
                    AllUsers = request.ShowAllUserData,
                    Exclude = GetAgents().Select(s => s.Id).ToArray()
                };
            var ret = await Http.PostAsJson<ListAgentsResponse>("api/Agent/List", req, request.CancellationToken);
            if (ret?.Agents != null)
            {
                return new ItemsProviderResult<GXAgent>(ret.Agents, ret.Count);
            }
        }
        catch (TaskCanceledException)
        {
            //Let the table component handle this.
            throw;
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
        finally
        {
            Notifier?.ProgressEnd();
        }
        return default;
    }

    protected override async Task OnInitializedAsync()
    {
        //Wait until table is loaded. Don't remove this or selector is null.
        await Task.Delay(1);
        try
        {
            Notifier.ProgressStart();
            Notifier.ClearStatus();
            if (_selected != null)
            {
                await _selected.RefreshDataAsync();
            }
            //Read available items.
            if (_available != null)
            {
                await _available.RefreshDataAsync();
            }
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
        finally
        {
            Notifier?.ProgressEnd();
        }
    }
}

